#include <zneo.h>
#include "types.h"
#include <STRING.H>
#include <MATH.H>
#include "ascii.h"
#include "system.h"
#include "LEDs.h"

void reset_position(void);

int ledPos, scrollRate, rowCounter, charCounter, scanCounter;
char ledString[MAX_STRING_LENGTH] = 0;
char displayedChars[NUM_LEDS+1] = 0;
char asciiDataForChars[NUM_LEDS][7];

extern scrollCounter;

boolean scrollOn;

#define D1 1
#define D2 2
#define D3 4
#define D4 8

void set_scroll_rate(int rateMills) {
	DI();
	scrollRate = rateMills;
	if (scrollRate == 0) {
		set_scroll_on(false);
	}
	scrollCounter = 0;
	reset_position();
	EI();
}

void set_led_text(char text[]) {
	int i;
	ledPos = 0;

	// Clear the current array
	for (i=0; i<MAX_STRING_LENGTH; i++) {
		ledString[i] = 0;
	}

	// Set the array to the provded text
	strcpy(ledString, text);

	reset_position();
}

void reset_position(void) {
	int i;
	for (i=0; i<NUM_LEDS; i++) {
		displayedChars[i] = ledString[i];
	}
}

void set_scroll_on(boolean scroll) {
	scrollOn = scroll;
}

void initialize_leds(void) {
	ledPos = 0;
	scrollOn = true;
	charCounter = 0;
	scanCounter = 0;
	rowCounter = 0;

	// Data Direction - Output
	PEDD = 0x00;
	PGDD = 0x00;
}

void display_character(short led, short rowNum, char code) {
	short anodeByte;
	int rowData;
	rowData = ascii_char[(code-32)][rowNum];
	anodeByte = anodes[rowNum];

	if (led == D1) {
		// 1. Set Cathodes High
		PEOUT |= 0x1F;

		// 2. Clear Cathodes to be Lit
		PEOUT &= ~rowData;

		// 3. Set Anodes High for Row rowCounter
		PGOUT = anodeByte;

		// 4. Switch Latch PE7
		PEOUT &= ~0x80;
		PEOUT |= 0x80;
	} else if (led == D2) {
		// 1. Set Cathodes High
		PEOUT |= 0x1F;

		// 2. Clear Cathodes to be Lit
		PEOUT &= ~rowData;

		// 3. Set Anodes High for Row rowCounter
		PGOUT = anodeByte;

		// 4. Switch Latch PG7
		PGOUT &= ~0x80;
		PGOUT |= 0x80;
	} else if (led == D3) {
		// 1. Set Cathodes High
		PEOUT |= 0x1F;

		// 2. Clear Cathodes to be Lit
		PEOUT &= ~rowData;

		// 3. Set Anodes High for Row rowCounter
		PGOUT = anodeByte;

		// 4. Switch Latch PE5
		PEOUT &= ~0x20;
		PEOUT |= 0x20;
	} else if (led == D4) {
		// 1. Set Cathodes High
		PEOUT |= 0x1F;

		// 2. Clear Cathodes to be Lit
		PEOUT &= ~rowData;

		// 3. Set Anodes High for Row rowCounter
		PGOUT = anodeByte;

		// 4. Switch Latch PE6
		PEOUT &= ~0x40;
		PEOUT |= 0x40;
	}
}


void scroll_led(void) {
	// We can turn scrolling on or off by setting scrollOn to true or false.
	if (scrollOn == true) {

		// This function simply shifts the "sliding window" displayedChars array to the right giving the illusion
		//   of the letters scrolling right-to-left.
		// Example:
		//   Text "    Hello World" ([ ] symbolizes a single 5x7 LED array)
		//     Iteration 0: [ ][ ][ ][ ]Hello World
		//     Iteration 1: [ ][ ][ ][H]ello World
		//     Iteration 2: [ ][ ][H][e]llo World
		//     Iteration 3: [ ][H][e][l]lo World
		//     Iteration 4: [H][e][l][l]o World
		//     Iteration 5: H[e][l][l][o] World
		//     Iteration 6: He[l][l][o][ ]World
		//     ...
		//     Iteration 14: Hello Worl[d][ ][ ][ ]
		//     Return to Iteration 0.

		// The iteration is stored in the variable ledPos, which will point to the first LED character.
		// The sliding window is displayedChars[0..MAX_LEDS]
		// The string is ledString[0..MAX_STRING_LENGTH]
		int i, j, overflow, charsRemaining;

		charsRemaining = strlen(ledString) - ledPos;

		if (charsRemaining >= NUM_LEDS) {
			// There is at least 1 character in the string that is still off the grid.
			// Shift everything one place.
			for (i = 0; i<NUM_LEDS; i++) {
				displayedChars[i] = ledString[ledPos + i];
			}
		} else {
			overflow = NUM_LEDS - charsRemaining;
			for (i = 0; i<(NUM_LEDS-overflow); i++) {
				displayedChars[i] = ledString[ledPos + i];
			}
			for (j = 0; j<overflow; j++) {
				displayedChars[i] = ledString[j];
				i++;
			}

		}
		// Increment the position counter.  If it exceeds the length of the string (plus a four space buffer), restart
		//   the scrolling.
		ledPos++;
		if (ledPos > strlen(ledString)-1) {
			ledPos = 0;
		}
	}
}

void scan_led(void) {
	
	// Hard coded for 4 LEDs.  Will come back to this to generalize it if time permits.
	display_character(D1, rowCounter, displayedChars[0]);
	display_character(D2, rowCounter, displayedChars[1]);
	display_character(D3, rowCounter, displayedChars[2]);
	display_character(D4, rowCounter, displayedChars[3]);

	rowCounter++;
	if (rowCounter > 6) {
		rowCounter = 0;
	}
}